#ifndef CGIENVIRONMENT_H_
#define CGIENVIRONMENT_H_

#include <exception>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <string>

#define AUTH_TYPE "AUTH_TYPE"
#define CONTENT_LENGTH "CONTENT_LENGTH"
#define CONTENT_TYPE "CONTENT_TYPE"
#define GATEWAY_INTERFACE "GATEWAY_INTERFACE"
#define PATH_INFO "PATH_INFO"
#define PATH_TRANSLATED "PATH_TRANSLATED"
#define QUERY_STRING "QUERY_STRING"
#define REMOTE_ADDR "REMOTE_ADDR"
#define REMOTE_HOST "REMOTE_HOST"
#define REMOTE_IDENT "REMOTE_IDENT"
#define REMOTE_USER "REMOTE_USER"
#define REQUEST_METHOD "REQUEST_METHOD"
#define SCRIPT_NAME "SCRIPT_NAME"
#define SERVER_NAME "SERVER_NAME"
#define SERVER_PORT "SERVER_PORT"
#define SERVER_PROTOCOL "SERVER_PROTOCOL"
#define SERVER_SOFTWARE "SERVER_SOFTWARE"

#define DOCUMENT_ROOT "DOCUMENT_ROOT"
#define REDIRECT_STATUS "REDIRECT_STATUS"

/** Maneja las meta-variables especificadas en el standard CGI/1.1 (RFC3875).
 * 	Las meta-variables son guardadas como variables de entorno del sistema.
 */
class CgiEnvironment {
private:
	/** Almacenan las variables de entorno.*/
	std::string authType;
	std::string contentLength;
	std::string contentType;
	std::string gatewayInterface;
	std::string pathInfo;
	std::string pathTranslated;
	std::string queryString;
	std::string remoteAddr;
	std::string remoteHost;
	std::string remoteIdent;
	std::string remoteUser;
	std::string requestMethod;
	std::string scriptName;
	std::string serverName;
	std::string serverPort;
	std::string serverProtocol;
	std::string serverSoftware;

	/** Las sgtes variables no son standard pero se utilizan ampliamente. */
	std::string documentRoot;
	std::string redirectStatus;

	/** Devuelve el valor de la variable de entorno o cadena vacia si
	 * 	no existe o tiene valor nulo.
	 * @param nombre Nombre de la variable de entorno a obtener.
	 * @return Contenido de la variable de entorno en formato de texto.
	 */
	std::string getEnvVar(const std::string &nombre) const;
	/** Devuelve el valor de la variable de entorno o -1 si no existe.
	 * @param nombre Nombre de la variable de entorno a obtener.
	 * @return Contenido de la variable de entorno en formato de entero largo.
	 */
	long getEnvVarLong(const std::string &nombre) const;

	/** Setea el valor de la variable de ambiente o arroja std::exception.
	 * @param envVar Referencia a la cadena que almacenerá la var de entorno.
	 * @param nombre Nombre de la variable de entorno a establecer.
	 * @param valor Cadena con el contenido a establecer.
	 */
	void setEnvVar(std::string &envVar, const std::string &nombre,
			const std::string &valor);
	/** Setea el valor de la variable de ambiente o arroja std::exception.
	 * @param envVar Referencia a la cadena que almacenerá la var de entorno.
	 * @param nombre Nombre de la variable de entorno a establecer.
	 * @param valor Entero largo con el contenido a establecer.
	 */
	void setEnvVarLong(std::string &envVar, const std::string &nombre,
			long valor);
public:
	CgiEnvironment() {}
	virtual ~CgiEnvironment() {}

	/** Devuelve el Auth_Type o cadena vacia en caso de error.*/
    std::string getAUTH_TYPE() const;
	/** Devuelve el Content_Length o -1 en caso de error.*/
	long getCONTENT_LENGTH() const;
	/** Devuelve el Content_Type o cadena vacia en caso de error.*/
    std::string getCONTENT_TYPE() const;
	/** Devuelve el Gateway_Interface o cadena vacia en caso de error.*/
    std::string getGATEWAY_INTERFACE() const;
	/** Devuelve el Path_Info o cadena vacia en caso de error.*/
    std::string getPATH_INFO() const;
	/** Devuelve el Path_Translated o cadena vacia en caso de error.*/
    std::string getPATH_TRANSLATED() const;
	/** Devuelve el Query_String o cadena vacia en caso de error.*/
    std::string getQUERY_STRING() const;
	/** Devuelve el Remote_Addr o cadena vacia en caso de error.*/
    std::string getREMOTE_ADDR() const;
	/** Devuelve el Remote_Host o cadena vacia en caso de error.*/
    std::string getREMOTE_HOST() const;
	/** Devuelve el Remote_Iden o cadena vacia en caso de error.*/
    std::string getREMOTE_IDENT() const;
	/** Devuelve el Remote_User o cadena vacia en caso de error.*/
    std::string getREMOTE_USER() const;
	/** Devuelve el Request_Method o cadena vacia en caso de error.*/
    std::string getREQUEST_METHOD() const;
	/** Devuelve el Script_Name o cadena vacia en caso de error.*/
    std::string getSCRIPT_NAME() const;
	/** Devuelve el Server_Name o cadena vacia en caso de error.*/
    std::string getSERVER_NAME() const;
	/** Devuelve el Server_Port o -1 en caso de error.*/
    long getSERVER_PORT() const;
	/** Devuelve el Server_Protocol o cadena vacia en caso de error.*/
    std::string getSERVER_PROTOCOL() const;
	/** Devuelve el Server_Software o cadena vacia en caso de error.*/
    std::string getSERVER_SOFTWARE() const;

	/** Variables no standard ampliamentes usadas. */
	/** Devuelve el Document_Root o cadena vacia en caso de error.*/
    std::string getDOCUMENT_ROOT() const;
	/** Devuelve el Redirect_Status o cadena vacia en caso de error.*/
    std::string getREDIRECT_STATUS() const;

    /** Setea Auth_Type o arroja std::exception en caso de error.
	 *  Es OBLIGATORIO en caso que el cliente requiera autenticación.*/
    void setAUTH_TYPE(const std::string &valor);
	/** Setea Content_Lenght o arroja std::exception en caso de error.
	 *  Es OBLIGATORIO en caso que el request tenga body.*/
    void setCONTENT_LENGTH(long valor);
	/** Setea Content_Type o arroja std::exception en caso de error.
	 *  Es OBLIGATORIO si el campo esta presente en el Http request header
	 *  del cliente.*/
    void setCONTENT_TYPE(const std::string &valor);
	/** Setea Gateway_Interface o arroja std::exception en caso de error.
	 *  Es OBLIGATORIO. Indica el lenguaje de comunicación entre el
	 *  server y el script.*/
    void setGATEWAY_INTERFACE(const std::string &valor);
	/** Setea Path_Info o arroja std::exception en caso de error.
	 *  Es OPCIONAL para indicar al script un nombre de archivo.
	 *  @param valor Ejemplo:/Mi%20Archivo.x */
    void setPATH_INFO(const std::string &valor);
	/** Setea Path_Translated o arroja std::exception en caso de error.
	 *  Es RECOMENDADO en caso que el RequestURI tenga un PATH_INFO asociado.
	 *  @param valor Ejemplo:/usr/local/www/htdocs/Mi%20Archivo.x */
    void setPATH_TRANSLATED(const std::string &valor);
	/** Setea Query_String o arroja std::exception en caso de error.
	 *  Es OBLIGATORIO. Guarda el script-uri o cadena vacia si no existe.*/
    void setQUERY_STRING(const std::string &valor);
	/** Setea Remote_Addr o arroja std::exception en caso de error.
	 *  Es OBLIGATORIO. Guarda la IP del cliente que envió el request. */
    void setREMOTE_ADDR(const std::string &valor);
	/** Setea Remote_Host o arroja std::exception en caso de error.
	 *  Es RECOMENDADO. Guarda el hostname del cliente que envió el request. */
    void setREMOTE_HOST(const std::string &valor);
	/** Setea Remote_Ident o arroja std::exception en caso de error.
	 *  Es OPCIONAL. Permite guardar una descricion genérica del cliente. */
    void setREMOTE_IDENT(const std::string &valor);
	/** Setea Remote_User o arroja std::exception en caso de error.
	 *  Es OBLIGATORIO en caso que se establezca AUTH_TYPE a Basic o Digest.
	 *  En ese caso debe contener el ID del usuario */
    void setREMOTE_USER(const std::string &valor);
	/** Setea Request_Method o arroja std::exception en caso de error.
	 *  Es OBLIGATORIO. Guarda el method o modo que se utilizó para el envío
	 *  de datos al script. Ej:"GET", "POST", etc. */
    void setREQUEST_METHOD(const std::string &valor);
	/** Setea Script_Name o arroja std::exception en caso de error.
	 *  Es OBLIGATORIO en caso que se requiera ejecutar un script.
	 *  Guarda el nombre del script en formato URI. */
    void setSCRIPT_NAME(const std::string &valor);
	/** Setea Server_Name o arroja std::exception en caso de error.
	 *  Es OBLIGATORIO. Contiene el nombre del servidor. Ej:localhost.*/
    void setSERVER_NAME(const std::string &valor);
	/** Setea Server_Port o arroja std::exception en caso de error.
	 *  Es OBLIGATORIO. Contiene el puerto donde se recibió la solicitud
	 *  del cliente.*/
    void setSERVER_PORT(long valor);
	/** Setea Server_Protocol o arroja std::exception en caso de error.
	 *  Es OBLIGATORIO. Contiene el protocolo y la versión con que se comunica
	 *  el servidor y el script. Ej:"HTTP/1.0", "INCLUDED".*/
    void setSERVER_PROTOCOL(const std::string &valor);
	/** Setea Server_Software o arroja std::exception en caso de error.
	 *  Es OBLIGATORIO. Contiene el nombre y version del servidor que solicita
	 *  la ejecucion del script CGI.*/
    void setSERVER_SOFTWARE(const std::string &valor);

	/** Variables no standard ampliamentes usadas. */
	/** Setea Document_Root o arroja std::exception en caso de error.
	 *  Es OPCIONAL. Contiene el path físico a la carpeta root del
	 *  servidor HTTP. */
    void setDOCUMENT_ROOT(const std::string &valor);
	/** Setea Redirect_Status o arroja std::exception en caso de error.
	 *  Es OPCIONAL. Contiene el código HTTP de respuesta al resultado de
	 *  una redirección del servidor al script. */
    void setREDIRECT_STATUS(const std::string &valor);
};

#endif /* CGIENVIRONMENT_H_ */
